﻿using CPAIS.Adapter;
using CPAIS.Model;
using CPAIS.Updater;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.SessionState;

namespace CPAIS.Web.AjaxHandlers
{

    public class HLDAAnalysisHandler : AjaxHandler
    {
        public HLDAAnalysisHandler(HttpContext context) : base(context) { }

        /// <summary>
        /// AJAX request:
        ///     LDAAnalysis
        /// 
        /// Request Parameters:
        ///     logName
        ///     K
        ///     alpha
        ///     beta
        ///     iterations
        ///     
        /// Response:
        ///     None
        ///     
        /// </summary>
        #region Ajax Request HLDAAnalysis

        public void HLDAAnalysis()
        {
            string logName = Params[Constants.LogName];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            HLDAGibbsAdapter adapter = mlManager.GetHLDAAdapter(logName);
            AnalysisUpdater updater = new AnalysisUpdater(Session, adapter,
                             int.Parse(Params[Constants.Iterations]));
            Session.Add(Constants.HLDAAnalysisUpdater, updater);
            ThreadPool.QueueUserWorkItem(DoAnalysising, updater);
        }

        private class AnalysisUpdater : ProgressUpdater
        {
            public HttpSessionState Session { get; set; }
            public HLDAGibbsAdapter Adapter { get; set; }
            public int K { get; set; }
            public double Alpha { get; set; }
            public double Beta { get; set; }
            public int Iterations { get; set; }

            public AnalysisUpdater(HttpSessionState session, HLDAGibbsAdapter adapter,  int iterations)
            {
                this.Session = session;
                this.Adapter = adapter;
              
                this.Iterations = iterations;
            }

            protected override bool OnUpdateMessage(string message)
            {
                if (Session[Constants.HLDAAnalysisUpdater] != null)
                {
                    return true;
                }
                return false;
            }

            protected override bool OnUpdateProgress(double progress)
            {
                if (Session[Constants.HLDAAnalysisUpdater] != null)
                {
                    return true;
                }
                return false;
            }
        }

        private void DoAnalysising(object state)
        {
            AnalysisUpdater updater = state as AnalysisUpdater;
            HLDAGibbsAdapter adapter = updater.Adapter;
            adapter.Execute(updater.Iterations, updater);
        }

        #endregion

        /// <summary>
        /// AJAX request:
        ///     CancelLDAAnalysis
        /// 
        /// Request Parameters:
        ///     logName
        /// 
        /// Response:
        ///     None
        /// </summary>
        #region Ajax Request CancelHLDAAnalysis

        public void CancelHLDAAnalysis()
        {
            Session.Remove(Constants.HLDAAnalysisUpdater);
        }

        #endregion

        /// <summary>
        /// AJAX request:   
        ///     QueryHLDAAnalysisProgress
        /// 
        /// Request Parameters:
        ///     logName
        /// 
        /// Response: 
        ///     QueryHLDAAnalysisProgress
        /// </summary>
        #region Ajax Request QueryHLDAAnalysisProgress

        public void QueryHLDAAnalysisProgress()
        {
            AnalysisUpdater updater = Session[Constants.HLDAAnalysisUpdater] as AnalysisUpdater;
            if (updater != null)
            {

                QueryHLDAAnalysisProgressPackage package = new QueryHLDAAnalysisProgressPackage
                {
                    state = updater.State.ToString(),
                    msg = updater.Message,
                    progress = updater.Progress
                };
                switch (updater.State)
                {
                    case UpdateState.Failed:
                    case UpdateState.Completed:
                        Session.Remove(Constants.HLDAAnalysisUpdater);
                        break;
                }
                WriteJson(package);
            }
        }

        private class QueryHLDAAnalysisProgressPackage
        {
            public string state { get; set; }
            public string msg { get; set; }
            public double progress { get; set; }
        }

        #endregion

        /// <summary>
        /// AJAX request:
        ///     GetHLDAAnalysisSummary
        /// 
        /// Request Parameters:
        ///     logName
        /// 
        /// Response: 
        ///     GetHLDAAnalysisSummaryPackage
        /// </summary>
        #region Ajax Request GetHLDAAnalysisSummary

        public void GetHLDAAnalysisSummary()
        {
            string logName = Params[Constants.LogName];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(logName);
            GetHLDAAnalysisSummaryPackage package = new GetHLDAAnalysisSummaryPackage();
            if (logModel == null)
            {
                package.state = false;
                package.data = null;
            }
            else
            {
                HLDAGibbsAdapter adapter = mlManager.GetHLDAAdapter(logName);
                package.state = true;
                package.data = new object[]
                {
                    new object[]{"Iterations", adapter.Iterations},
                     new object[]{"Document Size", adapter.DocumentSize},
                    new object[]{"Vocabulary Size", adapter.VocabularySize},
                    new object[]{"Topic Size", adapter.TopicSize},
                };
            }
            WriteJson(package);
        }

        private class GetHLDAAnalysisSummaryPackage
        {
            public bool state { get; set; }
            public object[] data { get; set; }
        }

        #endregion

        /// <summary>
        /// AJAX request:
        ///     GetHLDADocData
        /// 
        /// Request Parameters:
        ///     logName
        /// 
        /// Response: 
        ///     TraceDataPackage
        /// </summary>
        #region Ajax Request GetHLDADocData

        public void GetHLDADocData()
        {
            string path = Params[Constants.LogName];
            int start = int.Parse(Params[Constants.Start]);
            int limit = int.Parse(Params[Constants.Limit]);

            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            LogModel logModel = mlManager.GetLogModel(path);
            if (logModel != null)
            {
                List<TraceData> traceData = new List<TraceData>();
                foreach (var trace in logModel.Traces)
                {
                    TraceData data = new TraceData
                    {
                        pid = trace.ID
                    };
                    traceData.Add(data);
                }

                TraceDataPackage package = new TraceDataPackage();
                int count = traceData.Count;
                int left = count - start;
                package.total = count;
                package.items = traceData.GetRange(start, limit <= left ? limit : left);
                WriteJson(package);
            }
        }

        private class TraceData
        {
            public string pid { get; set; }
        }

        private class TraceDataPackage
        {
            public int total { get; set; }
            public List<TraceData> items { get; set; }
        }

        #endregion

        /// <summary>
        /// AJAX request:
        ///     GetHLDADocTopicProbability
        /// 
        /// Request Parameters:
        ///     logName
        ///     pid
        /// 
        /// Response: 
        ///     DocTopicProbabilityPackage
        /// </summary>
        #region Ajax Request GetHLDADocTopicProbability

        public void GetHLDADocTopicProbability()
        {
            string path = Params[Constants.LogName];
            string pid = Params[Constants.PID];
            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            HLDAGibbsAdapter adapter = mlManager.GetHLDAAdapter(path);
            if (adapter != null && adapter.DocTopicAssoc.ContainsKey(pid))
            {
                
                Dictionary<string, double> probs = adapter.DocTopicAssoc[pid];
                int length = probs.Count;
             
              
                DocTopicProbabilityPackage[] package = new DocTopicProbabilityPackage[length];
                int i = 0;
                foreach(string szTopic in probs.Keys)
                {
                        package[i] = new DocTopicProbabilityPackage();
                        package[i].topicNo = "CP Pattern " + szTopic;
                        package[i].probability = probs[szTopic];
                        i++;              
                }
                WriteJson(package);
            }
        }

        private class DocTopicProbabilityPackage
        {
            public string topicNo { get; set; }
            public double probability { get; set; }
        }

        #endregion

        /// <summary>
        /// AJAX request:
        ///     GetHLDATopicData
        /// 
        /// Request Parameters:
        ///     logName
        /// 
        /// Response: 
        ///     TopicDataPackage
        /// </summary>
        #region Ajax Request GetHLDATopicData

        public void GetHLDATopicData()
        {
            string path = Params[Constants.LogName];

            MLManager mlManager = Session[Constants.MLManager] as MLManager;
            HLDAGibbsAdapter adapter = mlManager.GetHLDAAdapter(path);
            TopicDataPackage package = new TopicDataPackage { count = 0, items = null };
            if (adapter != null)
            {
                var topics = adapter.TopicWordAssoc;
                package.count = topics.Length;
                package.items = new List<TopicData>();
                foreach (var topic in topics)
                {
                    TopicData topicData = new TopicData
                    {
                        prob = topic.Prob,
                        name = topic.name,
                        actions = new List<ActionData>()
                    };
                    foreach (var action in topic.Actions)
                    {
                        if (action.ActionProb >= 0.001)
                        {
                            topicData.actions.Add(new ActionData
                            {
                                name = action.ActionType,
                                prob = action.ActionProb
                            });
                        }
                    }
                    package.items.Add(topicData);
                }
            }
            WriteJson(package);
        }

        private class ActionData
        {
            public string name { get; set; }
            public double prob { get; set; }
        }

        private class TopicData
        {
            public double prob;
            public string name { get; set; }
            public List<ActionData> actions;
        }

        private class TopicDataPackage
        {
            public int count { get; set; }
            public List<TopicData> items { get; set; }
        }

        #endregion
    }
}